package com.open.capacity.finance.service.impl;

import com.mysql.cj.util.StringUtils;
import com.open.capacity.finance.constant.AuditWarnCategorys;
import com.open.capacity.finance.dao.*;
import com.open.capacity.finance.dto.audit_model_1.AuditModelStep2;
import com.open.capacity.finance.dto.audit_model_3.AuditModelStep1;
import com.open.capacity.finance.dto.echart.*;
import com.open.capacity.finance.entity.*;
import com.open.capacity.model.system.LoginAppUser;
import com.open.capacity.model.system.SysUser;
import com.open.capacity.nk.dto.NKReceiptTravelDto;
import com.open.capacity.user.service.SysDictDataService;
import com.open.capacity.user.service.SysDictService;
import com.open.capacity.user.service.SysUserRelationService;
import com.open.capacity.user.service.SysUserService;
import com.open.capacity.utils.DateUtil;
import com.open.capacity.utils.StringUtil;
import com.open.capacity.utils.SysUserUtil;
import javafx.util.Pair;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.open.capacity.commons.PageResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.open.capacity.commons.CodeEnum;

import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.collections4.MapUtils;

import com.open.capacity.finance.service.AuditModelWarnService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;


@Service
public class AuditModelWarnServiceImpl implements AuditModelWarnService {

    @Autowired
    private AuditModelWarnDao auditModelWarnDao;

    @Autowired
    private AuditModelDao auditModelDao;

    @Autowired
    private AuditModelWarnScopeDao warnScopeDao;
    @Autowired
    private AuditModelWarnPlanDao planDao;

    @Autowired
    private SysUserService userService;

    @Autowired
    private AuditModelWarnUserDao warnUserDao;

    @Autowired
    private SysUserRelationService relationService;

    @Autowired
    private SysDictDataService dictService;

    /**
     * 添加
     *
     * @param auditModelWarn
     */
    public int save(AuditModelWarn auditModelWarn) {
        return auditModelWarnDao.save(auditModelWarn);
    }

    /**
     * 修改
     *
     * @param auditModelWarn
     */
    public int update(AuditModelWarn auditModelWarn) {
        return auditModelWarnDao.update(auditModelWarn);
    }

    @Override
    public int read(Long id) {
        SysUser loginUser = SysUserUtil.getLoginAppUser();
        HashMap<String, Object> param = new HashMap<>();
        param.put("warnId", id);
        param.put("userId", loginUser.getId());
        List<AuditModelWarnUser> list = warnUserDao.findAll(param);
        for (AuditModelWarnUser item : list) {
            warnUserDao.updateReadFlag(item.getId());
        }
        return 1;
    }

    @Override
    public int ingore(Long id, Long day) {
        return auditModelWarnDao.updateIngoreFlag(id, DateUtil.addDay(new Date(), day));
    }

    @Override
    public int remark(Long id, String remark) {
        SysUser loginUser = SysUserUtil.getLoginAppUser();
        return auditModelWarnDao.updateRemark(id, remark, loginUser.getRealName(), new Date());
    }

    @Override
    @Transactional
    public int send(String ids, Integer status) {
        Assert.isTrue(StringUtil.isNotEmpty(ids), "找不到对应的模型");
        String[] idArray = ids.split(",");
        for (String id : idArray) {
            AuditModelWarn warn = auditModelWarnDao.findById(Long.valueOf(id));
            Assert.notNull(warn, "找不到对应的模型");

            if (status == 1) {
                Assert.isTrue(warn.getStatus() != 1, "该预警已经下发，无需重复下发");

                warn.setStatus(1);
                auditModelWarnDao.update(warn);

                List<Pair<String, String>> userIds = new ArrayList<>();
                List<AuditModelWarnScope> scopeList = warnScopeDao.findByModelId(warn.getModelId());
                if (CollectionUtils.isNotEmpty(scopeList)) {
                    if (scopeList.get(0).getObjectType().equals("All")) {
                        userService.findRoleUsers(new HashMap<>()).stream().collect(Collectors.toList()).forEach(
                                t -> {
                                    Pair<String, String> _t = new Pair<>(t.getCompanyId(), t.getId());
                                    userIds.add(_t);
                                }
                        );
                    } else {
                        for (AuditModelWarnScope warnScope : scopeList) {
                            if (warnScope.getObjectType().equals("1")) { //岗位
                                relationService.findByObjectId("Post", warnScope.getObjectId()).stream().collect(Collectors.toList()).forEach(
                                        t -> {
                                            Pair<String, String> _t = new Pair<>(t.getCompanyId(), t.getId());
                                            userIds.add(_t);
                                        }
                                );
                            } else if (warnScope.getObjectType().equals("2")) { //角色
                                relationService.findByObjectId("Role", warnScope.getObjectId()).stream().collect(Collectors.toList()).forEach(
                                        t -> {
                                            Pair<String, String> _t = new Pair<>(t.getCompanyId(), t.getId());
                                            userIds.add(_t);
                                        }
                                );
                            } else if (warnScope.getObjectType().equals("3")) { //用户
                                Pair<String, String> _t = new Pair<>(warnScope.getCompanyId(), warnScope.getObjectId());
                                userIds.add(_t);
                            }
                        }
                    }
                }

                AuditModel model = auditModelDao.findById(warn.getModelId());
                Date now = new Date();
                //忽略结果集相同的告警
                for (Pair user : userIds) {
                    //判断是否需要通知对方
                    if (user.getKey().equals(warn.getCompanyId()) && needWarn(model.getId(), warn.getCompanyId())) {
                        AuditModelWarnUser warnUser = new AuditModelWarnUser();
                        warnUser.setWarnId(warn.getId());
                        warnUser.setWarnLevel(warn.getWarnLevel());
                        warnUser.setCreateTime(now);
                        warnUser.setDealFlag(warn.getDealFlag());
                        warnUser.setDealEnddate(warn.getDealEnddate());
                        warnUser.setUserId(user.getValue().toString());
                        warnUserDao.save(warnUser);
                    }
                }
            } else {
                Assert.isTrue(warn.getStatus() == 1, "该预警未下发，无需取消");
                warn.setStatus(0);
                auditModelWarnDao.update(warn);

                warnUserDao.deleteByWarnId(warn.getId());
            }
        }
        return 1;
    }


    /**
     * 删除
     *
     * @param ids
     */
    @Transactional
    public int delete(String ids) {
        String[] idArray = ids.split(",");
        for (String id : idArray) {
            auditModelWarnDao.delete(Long.valueOf(id));
        }
        return 1;
    }

    /**
     * 查询记录
     *
     * @param id
     * @return
     */
    public AuditModelWarn findById(Long id) {
        return auditModelWarnDao.findById(id);
    }

    @Override
    public AuditModelWarn findLastByModelId(String modelId, String companyId, String planId) {
        Map<String, Object> param = new HashMap<>();
        if (StringUtils.isNullOrEmpty(planId)) {
            AuditModelWarnPlan last = planDao.findLast();
            if (last != null) {
                param.put("planId", last.getId());
            }
        } else {
            param.put("planId", planId);
        }

        param.put("modelId", modelId);
        param.put("companyId", companyId);

        List<AuditModelWarn> list = auditModelWarnDao.findAll(param);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public AuditWarnDto countWarn() {
        SysUser loginUser = SysUserUtil.getLoginAppUser();
        Map<String, Object> param = new HashMap<>();

        //市院角色查看全局的预警
        if (!Arrays.asList(loginUser.getRoleIds().split(",")).contains("1")) {
            param.put("companyId", loginUser.getCompanyId());
        }
        List<AuditModelWarn> warnList = auditModelWarnDao.findAll(param);

        param.put("status", 1);
        List<AuditModel> modelList = auditModelDao.findAll(param);


        AuditWarnDto dto = new AuditWarnDto();
        dto.setTotalCount(modelList.size());

        dto.setNomalCount(modelList.size() - warnList.size());
        dto.setErrorCount(warnList.size());
        dto.setDealDoingCount(warnList.stream().filter(t -> t.getDealFlag().equals(1)).count());
        dto.setDealCompleteCount(warnList.stream().filter(t -> t.getDealFlag().equals(2)).count());


        //组装echart图表数据
        List<CategoryWarnDto> categoryWarnList = packetEchartData(warnList);

        //组装单位预警分类统计表格
        //预警总数
        List<CategoryCompanyWarnDetailDto> companyWarnDetailList1 = packetCompanyWarnData(warnList, null);
        //已整改
        List<CategoryCompanyWarnDetailDto> companyWarnDetailList2 = packetCompanyWarnData(warnList, 2);
        //整改中
        List<CategoryCompanyWarnDetailDto> companyWarnDetailList3 = packetCompanyWarnData(warnList, 1);
        dto.setEchartData(categoryWarnList);

        Map<String, Long> collect = warnList.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));
        List<KeyValuePair> echartCompanys = new ArrayList<>();
        for (Map.Entry<String, Long> entry : collect.entrySet()) {
            KeyValuePair item = new KeyValuePair();
            item.setName(entry.getKey().replaceAll("广州市", "").replaceAll("人民检察院", "").replaceAll("区", ""));
            item.setValue(Integer.parseInt(entry.getValue().toString()));
            echartCompanys.add(item);
        }
        echartCompanys.sort(Comparator.comparing(t -> Integer.valueOf(t.getValue())));
        dto.setEchartCompanys(echartCompanys);

        dto.setEchartCategories(categoryWarnList.stream().map(t -> {
            KeyValuePair item = new KeyValuePair();
            item.setName(t.getDrilldown().getName());
            item.setValue(t.getY());
            return item;
        }).collect(Collectors.toList()));

        dto.setCompanywarnDetail1(companyWarnDetailList1);
        dto.setCompanywarnDetail2(companyWarnDetailList2);
        dto.setCompanywarnDetail3(companyWarnDetailList3);
        return dto;
    }

    @Override
    public List<CompanyWarnDetailDto> groupByModelId() {
        SysUser loginUser = SysUserUtil.getLoginAppUser();
        Map<String, Object> param = new HashMap<>();

        //市院角色查看全局的预警
        if (!Arrays.asList(loginUser.getRoleIds().split(",")).contains("1")) {
            param.put("companyId", loginUser.getCompanyId());
        }
        List<AuditModelWarn> warnList = auditModelWarnDao.findAll(param);
        List<CompanyWarnDetailDto> companyWarnDetailDtoList = new ArrayList<>();
        CompanyWarnDetailDto item;

        TreeMap<String, List<AuditModelWarn>> collect = warnList.stream().collect(Collectors.groupingBy(t -> t.getModelId() + "_" + t.getModelName() + "_" + t.getDefaultKjnd(), TreeMap::new, Collectors.toList()));
        for (Map.Entry<String, List<AuditModelWarn>> entry : collect.entrySet()) {
            item = new CompanyWarnDetailDto();
            String modelId = entry.getKey().split("_")[0];
            String modelName = entry.getKey().split("_")[1];
            Integer defaultKjnd = Integer.valueOf(entry.getKey().split("_")[2]);
            item.setModelId(modelId);
            item.setCodeAndName(modelName);
            item.setDefaultKjnd(defaultKjnd);

            item.setC00(entry.getValue().stream().filter(t -> "00".equals(t.getCompanyId())).count());
            item.setC01(entry.getValue().stream().filter(t -> "01".equals(t.getCompanyId())).count());
            item.setC02(entry.getValue().stream().filter(t -> "02".equals(t.getCompanyId())).count());
            item.setC03(entry.getValue().stream().filter(t -> "03".equals(t.getCompanyId())).count());
            item.setC04(entry.getValue().stream().filter(t -> "04".equals(t.getCompanyId())).count());
            item.setC05(entry.getValue().stream().filter(t -> "05".equals(t.getCompanyId())).count());
            item.setC06(entry.getValue().stream().filter(t -> "06".equals(t.getCompanyId())).count());
            item.setC07(entry.getValue().stream().filter(t -> "07".equals(t.getCompanyId())).count());
            item.setC08(entry.getValue().stream().filter(t -> "08".equals(t.getCompanyId())).count());
            item.setC09(entry.getValue().stream().filter(t -> "09".equals(t.getCompanyId())).count());
            item.setC10(entry.getValue().stream().filter(t -> "10".equals(t.getCompanyId())).count());
            item.setC11(entry.getValue().stream().filter(t -> "11".equals(t.getCompanyId())).count());

            companyWarnDetailDtoList.add(item);
        }

        companyWarnDetailDtoList.sort(Comparator.comparing(t -> Integer.valueOf(t.getModelId())));
        return companyWarnDetailDtoList;
    }

    //组装echart图表数据
    private List<CategoryWarnDto> packetEchartData(List<AuditModelWarn> warnList) {
        List<CategoryWarnDto> categoryWarnDtoList = new ArrayList<>();
        CategoryWarnDto item = new CategoryWarnDto();
        Map<String, Long> collect;
        CategoryCompanyWarnDto companyWarnDto = new CategoryCompanyWarnDto();

        //账务处理
        List<AuditModelWarn> finance = warnList.stream().filter(t -> AuditWarnCategorys.FINANCE.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(finance)) {
            item = new CategoryWarnDto();
            item.setY(finance.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("账务处理");
            collect = finance.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }


        //支付管理
        List<AuditModelWarn> pay = warnList.stream().filter(t -> AuditWarnCategorys.PAY.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(pay)) {
            item = new CategoryWarnDto();
            item.setY(pay.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("支付管理");
            collect = pay.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }


        //资金效益
        List<AuditModelWarn> reimburse = warnList.stream().filter(t -> AuditWarnCategorys.REIMBURSE.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(reimburse)) {
            item = new CategoryWarnDto();
            item.setY(reimburse.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("资金效益");
            collect = reimburse.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }


        //固定资产
        List<AuditModelWarn> asset = warnList.stream().filter(t -> AuditWarnCategorys.ASSET.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(asset)) {
            item = new CategoryWarnDto();
            item.setY(asset.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("固定资产");
            collect = asset.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }


        //公车管理
        List<AuditModelWarn> car = warnList.stream().filter(t -> AuditWarnCategorys.CAR.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(car)) {
            item = new CategoryWarnDto();
            item.setY(car.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("公车管理");
            collect = car.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }


        //政府采购
        List<AuditModelWarn> purchase = warnList.stream().filter(t -> AuditWarnCategorys.PURCHASE.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(purchase)) {
            item = new CategoryWarnDto();
            item.setY(purchase.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("政府采购");
            collect = purchase.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }


        //其他
        List<AuditModelWarn> other = warnList.stream().filter(t -> AuditWarnCategorys.OTHER.getCode().equals(t.getCategory())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(other)) {
            item = new CategoryWarnDto();
            item.setY(other.size());
            companyWarnDto = new CategoryCompanyWarnDto();
            companyWarnDto.setName("其他");
            collect = other.stream().collect(Collectors.groupingBy(AuditModelWarn::getCompanyName, Collectors.counting()));

            companyWarnDto.setCategories(collect.keySet().stream().map(t -> t.substring(6, 8)).collect(Collectors.toList()).toArray(new String[0]));
            companyWarnDto.setData(collect.values().toArray(new Long[0]));
            item.setDrilldown(companyWarnDto);
            categoryWarnDtoList.add(item);
        }
        return categoryWarnDtoList;
    }

    //组装单位预警分类统计表格
    private List<CategoryCompanyWarnDetailDto> packetCompanyWarnData(List<AuditModelWarn> warnList, Integer dealFlag) {
        List<CategoryCompanyWarnDetailDto> companyWarnDetailDtoList = new ArrayList<>();
        CategoryCompanyWarnDetailDto item;

        TreeMap<String, List<AuditModelWarn>> collect;
        if (dealFlag != null) {
            collect = warnList.stream().filter(t -> t.getDealFlag() == dealFlag).collect(Collectors.groupingBy(t -> t.getCompanyId() + "_" + t.getCompanyName(), TreeMap::new, Collectors.toList()));
        } else {
            collect = warnList.stream().collect(Collectors.groupingBy(t -> t.getCompanyId() + "_" + t.getCompanyName(), TreeMap::new, Collectors.toList()));
        }
        for (Map.Entry<String, List<AuditModelWarn>> entry : collect.entrySet()) {
            item = new CategoryCompanyWarnDetailDto();
            item.setCompanyId(entry.getKey().split("_")[0]);
            item.setCompanyName(entry.getKey().split("_")[1]);
            item.setFinance(entry.getValue().stream().filter(t -> AuditWarnCategorys.FINANCE.getCode().equals(t.getCategory())).count());
            item.setPay(entry.getValue().stream().filter(t -> AuditWarnCategorys.PAY.getCode().equals(t.getCategory())).count());
            item.setReimburse(entry.getValue().stream().filter(t -> AuditWarnCategorys.REIMBURSE.getCode().equals(t.getCategory())).count());
            item.setAsset(entry.getValue().stream().filter(t -> AuditWarnCategorys.ASSET.getCode().equals(t.getCategory())).count());
            item.setPurchase(entry.getValue().stream().filter(t -> AuditWarnCategorys.PURCHASE.getCode().equals(t.getCategory())).count());
            item.setCar(entry.getValue().stream().filter(t -> AuditWarnCategorys.CAR.getCode().equals(t.getCategory())).count());
            item.setOther(entry.getValue().stream().filter(t -> AuditWarnCategorys.OTHER.getCode().equals(t.getCategory())).count());
            companyWarnDetailDtoList.add(item);
        }
        return companyWarnDetailDtoList;
    }

    @Override
    public boolean needWarn(String modelId, String companyId) {
        AuditModelWarn userNeedWarnDate = auditModelWarnDao.findNeedWarnDate(modelId, companyId);
        if (userNeedWarnDate != null && userNeedWarnDate.getDealEnddate().compareTo(new Date()) > 0) {
            return false;
        }
        return true;
    }

    /**
     * 分页
     *
     * @param params
     * @return
     */
    public PageResult<AuditModelWarn> pageMy(Map<String, Object> params) {
        LoginAppUser loginUser = SysUserUtil.getLoginAppUser();

        //设置分页信息，分别是当前页数和每页显示的总记录数【记住：必须在mapper接口中的方法执行之前设置该分页信息】
        if (MapUtils.getInteger(params, "page") != null && MapUtils.getInteger(params, "limit") != null)
            PageHelper.startPage(MapUtils.getInteger(params, "page"), MapUtils.getInteger(params, "limit"), true);

        params.put("userId", loginUser.getId());

        List<AuditModelWarn> list = auditModelWarnDao.findMy(params);

        PageInfo<AuditModelWarn> pageInfo = new PageInfo(list);

        return PageResult.<AuditModelWarn>builder().data(pageInfo.getList()).resp_code(CodeEnum.SUCCESS.getCode()).count(pageInfo.getTotal()).build();
    }

    /**
     * 全部告警
     *
     * @param params
     * @return
     */
    public PageResult<AuditModelWarn> pageAll(Map<String, Object> params) {
        LoginAppUser loginUser = SysUserUtil.getLoginAppUser();

        //设置分页信息，分别是当前页数和每页显示的总记录数【记住：必须在mapper接口中的方法执行之前设置该分页信息】
        if (MapUtils.getInteger(params, "page") != null && MapUtils.getInteger(params, "limit") != null)
            PageHelper.startPage(MapUtils.getInteger(params, "page"), MapUtils.getInteger(params, "limit"), true);

        if (!loginUser.getCompanyId().equals("00")) {
            params.put("userId", loginUser.getId());
        }

        List<AuditModelWarn> list = auditModelWarnDao.findAll(params);

        PageInfo<AuditModelWarn> pageInfo = new PageInfo(list);

        return PageResult.<AuditModelWarn>builder().data(pageInfo.getList()).resp_code(CodeEnum.SUCCESS.getCode()).count(pageInfo.getTotal()).build();
    }

    /**
     * 列表
     *
     * @param params
     * @return
     */
    public List<AuditModelWarn> findAll(Map<String, Object> params) {
        List<AuditModelWarn> list = auditModelWarnDao.findAll(params);
        return list;
    }
}
